上一篇把 AI 壓測報告需要的資料與整體架構定下來,這篇說明實作的部分。
我們先用一個壓測案例來說明實作流程,這次使用薪轉日的情境。
薪轉日通常會有大量使用者在短時間內登入,接著查詢帳戶、確認薪資是否入帳,再進行轉帳或查詢交易紀錄。這次模擬 1,000 位使用者在一分鐘內登入 Lite-Bank,登入成功後先查詢帳戶與餘額,再依照下面的比例執行後續操作:
每位使用者的 Session 維持 15 分鐘,這段時間會持續執行對應的操作。整個情境會經過 api-gateway、user-service、account-service、teller-service 與 transaction-service,所以這次要驗證的是完整業務流程在指定負載下的效能與穩定性。
接下來就用這個案例來進行說明。
起點是 manifest.yaml。它會在壓測前記錄測試類型、測試目的、業務操作、觀測服務、負載設定與驗收門檻。
以下節錄一小段設定:
test:
type: BUSINESS_JOURNEY
name: Lite-Bank 發薪日流程
objective: 驗證指定負載下,登入與後續銀行操作是否達到驗收條件
target:
operations:
- id: login
name: 使用者登入
protocol: HTTP
method: POST
route: /api/v1/auth/login
- id: transfer
name: 執行 TWD 轉帳
protocol: HTTP
method: POST
route: /api/v1/transfers
services:
- service: api-gateway
metrics:
type: gateway
- service: user-service
metrics:
type: application
- service: teller-service
metrics:
type: application
acceptance:
- id: login-latency
type: LATENCY_P99
threshold_ms: 1000
scope:
operation: login
- id: transfer-latency
type: LATENCY_P99
threshold_ms: 3000
scope:
operation: transfer
test 記錄測試名稱、目的與類型。這裡使用 BUSINESS_JOURNEY,代表這次要驗證登入、查詢帳戶與轉帳的完整業務流程。
K6 腳本會替每種 request 設定 operation tag,用來分開統計各項業務操作。Manifest 的 operations 使用相同的 ID,再補上操作名稱、HTTP method 與 route。以登入為例,K6 將 request 標記為 login,Manifest 也使用 id: login。後續程式讀取 K6 summary 時,就能將登入的數值對應到「使用者登入」與 /api/v1/auth/login。轉帳也是同樣的做法,兩邊都使用 transfer。
最後由 acceptance 設定每個操作的驗收門檻。第一條使用 operation: login,程式會從 K6 summary 取得登入的 P99,檢查是否低於 1 秒。第二條使用 operation: transfer,會取得轉帳的 P99,門檻是 3 秒。Manifest 裡的 operation id、K6 request tag 與 acceptance 使用相同名稱,程式才能找到正確的數值。
services 負責另一件事:寫下這次要從 Prometheus 觀測哪些服務。metrics.type 決定要套用哪一組 metrics query;gateway 會多查 route 資料,application 會查一般應用程式與 Kubernetes metrics。
還有一個區段是 workload,以下是節錄:
workload:
tool: K6
planned_duration: PT15M
scenarios:
- id: payday_journey
executor: CONSTANT_ARRIVAL_RATE
rate: 1000
time_unit: PT1M
arrival_duration: PT1M
pre_allocated_vus: 1001
max_vus: 1001
completed_metric: iterations
workload 主要記錄 K6 施加什麼負載。這個案例使用 CONSTANT_ARRIVAL_RATE,在一分鐘內啟動 1,000 次薪轉日流程,每位使用者持續操作 15 分鐘。K6 會預先準備 1,001 個 VUs,最多也使用 1,001 個,避免啟動使用者時因為 VUs 不足而來不及執行。
completed_metric: iterations 表示後續會用 K6 完成的 iteration 數量,確認實際跑完多少次流程。這些設定會放進 Bundle 與報告,讓 AI 知道本次結果是在什麼負載條件下量到的。實際執行仍由 K6 腳本負責,兩邊的設定需要保持一致。
將這份 YAML 交給 AI 分析前,測試人員要先填好測試類型、operations、觀測的 services、workload 與 acceptance,說明這次要測什麼、如何施加負載,以及最後的驗收標準。
K6 壓測完成後會產生 summary JSON。程式會先從 K6 summary 確認正式測量時間,再依照 Manifest 的 services 與 metrics.type 展開對應的 PromQL,向 Prometheus 查詢 K6、應用程式與 Kubernetes metrics。服務 metrics 會多收集壓測結束後五分鐘的恢復期,確認負載停止後 CPU、Memory 等資源是否恢復;K6 metrics 則只保留正式壓測期間的資料。部分 metrics 會透過 PromQL 以固定間隔查詢,例如 CPU 使用率在 15 分鐘的正式壓測期間每 30 秒取一個資料點,包含開始與結束時間,最後會取得 31 個資料點。
查詢結果會保存成 prometheus-snapshot.json。Snapshot 會記錄實際執行的 PromQL、查詢時間、Prometheus 回傳結果與查詢狀態,保留當下取得的原始資料。即使 Prometheus 的歷史資料之後過期,也能回頭確認當時查了什麼,以及實際拿到哪些資料。
抓取完成後,程式會將 Snapshot 資訊回寫到 Manifest:
artifacts:
prometheus_snapshot:
path: results/payday-run/prometheus-snapshot.json
format: PROM_QUERY_SNAPSHOT
sha256: <SHA-256>
path 記錄 Snapshot 的位置,format 表示檔案格式,sha256 用來確認後續讀到的檔案沒有被替換或修改。這三個欄位由程式產生,不需要測試人員手動填寫。
Snapshot 保存的是 Prometheus 查回來的原始資料,還需要先整理成 AI 能直接分析的特徵,將每項 metric 的時間序列分成邊界、正式測量與恢復期,檢查資料是否完整,再計算最大值、最小值與平均值等摘要。實際產物是 JSON,以下用 YAML 節錄 CPU 使用率的特徵化結果:
queries:
- query_id: cpu_usage
metric:
type: RATE
unit: cpu_cores
series:
- labels:
pod: user-service-7b8c9d
container: user-service
observations:
boundary:
- at: "2026-08-20T03:41:03.533Z"
state: FINITE
value: "0.08"
# 其餘邊界資料點省略
measurement:
- at: "2026-08-20T03:43:03.533Z"
state: FINITE
value: "0.42"
- at: "2026-08-20T03:43:33.533Z"
state: ABSENT
# 其餘正式測量資料點省略
recovery:
- at: "2026-08-20T03:56:33.533Z"
state: FINITE
value: "0.15"
# 其餘恢復期資料點省略
coverage:
expected_points: 27
state_counts:
FINITE: 26
ABSENT: 1
continuity_breaks:
- position: MIDDLE
starts_at: "2026-08-20T03:43:33.533Z"
ends_at: "2026-08-20T03:43:33.533Z"
point_count: 1
summaries:
observed_min:
status: PARTIAL_COVERAGE
value: 0.18
observed_max:
status: PARTIAL_COVERAGE
value: 0.92
observed_mean:
status: NOT_COMPUTABLE
reason: INCOMPLETE_MEASUREMENT
observations 會保留完整時間序列,並分成 boundary、measurement 與 recovery。boundary 是壓測剛開始的緩衝資料,這個案例的 CPU 使用率用 rate() 計算,前兩分鐘會帶到壓測開始前的資料,所以前四個資料點只留作計算參考。measurement 保存正式壓測期間用來分析的資料,recovery 保存壓測結束後五分鐘的資料,用來確認資源是否恢復。
每個資料點都會標記狀態。FINITE 代表有取得數值,ABSENT 代表該時間點沒有資料,程式不會把缺值補成 0。coverage 用來確認資料有沒有收齊。這個例子原本應該有 27 個資料點,實際取得 26 個,另外 1 個是缺值。continuity_breaks 會接著記錄缺值發生的時間、位置與持續多久。
最後,summaries 會依照 metrics 類型計算適用的摘要。這個例子少了一個資料點,所以最大值與最小值標記為 PARTIAL_COVERAGE,平均值則標記為 NOT_COMPUTABLE。AI 看到這些欄位後,可以分清楚完整結果、部分資料與無法計算的情況,同時還能回到 observations 核對原始資料點。
完成特徵化後,程式會拿 Manifest 的 acceptance 與 K6 summary 的實測值進行比對。這次登入的 P99 是 30,171.80 ms,超過 1,000 ms 的門檻;轉帳的 P99 是 242.95 ms,低於 3,000 ms,以下節錄登入與轉帳的判定結果:
verdict: FAIL
conditions:
- id: login-latency
verdict: FAIL
threshold_ms: 1000
actual: 30171.80
unit: ms
- id: transfer-latency
verdict: PASS
threshold_ms: 3000
actual: 242.95
unit: ms
每一條條件都會保留門檻、實測值與判定結果。只要有一條條件是 FAIL,整體結果就是 FAIL;需要的數值缺少時,則會標記為 UNDETERMINED。這個判定由固定程式完成,AI 不會自行決定門檻或修改結果。
驗收結果完成後,程式會將前面產生的資料組合成 Bundle。以下用 YAML 簡化呈現它的主要內容:
run:
id: payday-15m-business-journey
measurement:
start_at: "2026-09-12T14:41:59.130Z"
end_at: "2026-09-12T14:56:59.130Z"
test:
type: BUSINESS_JOURNEY
name: Lite-Bank 發薪日流程
feature_artifact:
queries:
- query_id: cpu_usage
# observations、coverage 與 summaries 省略
k6:
workload:
planned_duration: PT15M
results:
operations:
login:
status: OBSERVED
http_req_duration_ms:
p99: 30171.80
transfer:
status: OBSERVED
http_req_duration_ms:
p99: 242.95
acceptance:
verdict: FAIL
conditions:
- id: login-latency
verdict: FAIL
- id: transfer-latency
verdict: PASS
topology:
services:
- service: api-gateway
- service: user-service
- service: teller-service
operations:
- id: login
- id: transfer
run 與 test 說明這次執行的時間和目的,feature_artifact 提供 K6、服務與 Kubernetes metrics 的完整特徵,k6 保存負載設定與使用者實際感受到的結果,acceptance 記錄驗收判定,topology 是從 manifest.yaml 的 target 組出來,交代這次觀測的服務與業務操作。
這篇先用薪轉日壓測說明 AI 分析前的資料準備流程實作。測試人員先用 Manifest 定義測試情境、觀測服務、負載與驗收門檻,程式再收集 Prometheus 資料、建立 Snapshot、整理特徵、判斷驗收結果,最後組合成 Bundle。
壓測情境、K6 結果、服務 metrics 與驗收結果都已經整理完成。下一篇再從 Bundle 接著往下,說明 AI 如何根據這些資料產生壓測報告。
今天就先寫到這,我們明天見!